package com.taoyuanx.boot.business.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.taoyuanx.boot.business.TokenBusiness;
import com.taoyuanx.boot.eum.TokenResult;
import com.taoyuanx.boot.eum.TokenType;
import com.taoyuanx.boot.utils.HashUtil;
import com.taoyuanx.boot.utils.RSAUtil;

/**
 * @author admin token 格式 openKey.desc.sign base64 编码 desc 格式 xx_xx_xx 暂定
 *         type_endTime
 *         
 */
@Component
public class TokenBusinessImpl implements TokenBusiness {
	public static final String TOKEN_SPLIT = ".";//分隔符
	public static final String TOKEN_DESC_SPLIT = "_";//desc分隔符
	public static final Logger log = LoggerFactory.getLogger(TokenBusinessImpl.class);
	//有条件的同学 可以增加redis cache 
	public static final Cache<String, String> commonCache = CacheBuilder.newBuilder().maximumSize(500)
			.initialCapacity(20)
			.expireAfterWrite(TimeUnit.MILLISECONDS.toHours(TokenType.COMMON_TOKEN.timeout), TimeUnit.HOURS).build();// 通用token key tokenHash value 为业务字段
																														// 默认过期时间为
																														// 4个小时
	public static final Cache<String, Integer> updateCache = CacheBuilder.newBuilder().maximumSize(500)
			.initialCapacity(20)
			.expireAfterWrite(TimeUnit.MILLISECONDS.toHours(TokenType.REFRESH_TOKEN.timeout), TimeUnit.HOURS).build();// 更新token
																														// 默认过期时间为
																														// 5个小时
																														// 只能使用一次

	@Override
	public String buildToken(String openKey, String businessDesc, TokenType type) {
		try {
			StringBuilder tokenBuf = new StringBuilder(Base64.encodeBase64String(openKey.getBytes()));
			if (null == businessDesc) {
				businessDesc = type.type+"_"+String.valueOf(System.currentTimeMillis() + type.timeout);
			} else {
				businessDesc +=type.type+"_"+String.valueOf(System.currentTimeMillis() + type.timeout);
			}
			switch (type) {
			case COMMON_TOKEN: {
				String keyWordDesc=openKey+TOKEN_DESC_SPLIT+businessDesc;
				String sign = RSAUtil.signData((keyWordDesc).getBytes(), null, null);
				tokenBuf.append(TOKEN_SPLIT).append(Base64.encodeBase64String(businessDesc.getBytes())).append(TOKEN_SPLIT)
						.append(sign);
				String token = tokenBuf.toString();
				String tokenHash = HashUtil.hash(HashUtil.MD5, token.getBytes());
				commonCache.put(tokenHash, keyWordDesc);
				return token;
			}
			case REFRESH_TOKEN: {
				String keyWordDesc=openKey+TOKEN_DESC_SPLIT+businessDesc;
				String sign = RSAUtil.signData((keyWordDesc).getBytes(), null, null);
				tokenBuf.append(TOKEN_SPLIT).append(Base64.encodeBase64String(businessDesc.getBytes())).append(TOKEN_SPLIT)
						.append(sign);
				return tokenBuf.toString();
			}
			default: {
				String keyWordDesc=openKey+TOKEN_DESC_SPLIT+businessDesc;
				String sign = RSAUtil.signData((openKey + businessDesc).getBytes(), null, null);
				tokenBuf.append(TOKEN_SPLIT).append(Base64.encodeBase64String(businessDesc.getBytes())).append(TOKEN_SPLIT)
						.append(sign);
				String token = tokenBuf.toString();
				String tokenHash = HashUtil.hash(HashUtil.MD5, token.getBytes());
				commonCache.put(tokenHash, keyWordDesc);
				return token;
			}
			}
		} catch (Exception e) {
			log.error("生成token异常{},openKey:{}", e, openKey);
			return null;
		}

	}

	@Override
	public Object vafyToken(String token) {
		try {
			if (StringUtils.isEmpty(token))
				return TokenResult.NULL;
			String tokenHash = HashUtil.hash(HashUtil.MD5, token.getBytes());
			String keyWordDesc=commonCache.getIfPresent(tokenHash);
			if (null !=keyWordDesc ) {// 如果缓存中有，直接返回
				return keyWordDesc;
			}
			String[] tokenSplits = token.split("\\" + TOKEN_SPLIT);
			String openKey = new String(Base64.decodeBase64(tokenSplits[0]));
			String businessDesc = new String(Base64.decodeBase64(tokenSplits[1]));
			String[] descSplits = businessDesc.split(TOKEN_DESC_SPLIT);
			if(null==descSplits||descSplits.length<2){
				return TokenResult.TOKEN_FORMAT_ERR;
			}
			String sign = tokenSplits[2];
			Long endTime = Long.valueOf(descSplits[descSplits.length-1]);
			if (endTime < System.currentTimeMillis()) {
				return TokenResult.EXPIRE;
			}
			keyWordDesc=openKey+TOKEN_DESC_SPLIT+businessDesc;
			boolean vefy = RSAUtil.vefySign(keyWordDesc, sign, null);
			if (vefy) {
				return keyWordDesc;
			} else
				return TokenResult.VAFY_SIGN_ERR;
		} catch (Exception e) {
			log.error("验证token异常{}", e);
			return TokenResult.TOKEN_FORMAT_ERR;
		}

	}

	@Override
	public Object refreshToken(String updateToken) {
		try {
			if (StringUtils.isEmpty(updateToken))
				return TokenResult.NULL;
			String tokenHash = HashUtil.hash(HashUtil.MD5, updateToken.getBytes());
			if (null != updateCache.getIfPresent(tokenHash)) {// 如果缓存中有，直接返回
				return TokenResult.LIMIT_ERR;
			}
			String[] tokenSplits = updateToken.split("\\" + TOKEN_SPLIT);
			String openKey = new String(Base64.decodeBase64(tokenSplits[0]));
			String desc = new String(Base64.decodeBase64(tokenSplits[1]));
			String[] descSplits = desc.split(TOKEN_DESC_SPLIT);
			if(null==descSplits||descSplits.length<2){
				return TokenResult.TOKEN_FORMAT_ERR;
			}
			if(!TokenType.REFRESH_TOKEN.type.equals(descSplits[descSplits.length-2])){
				return TokenResult.NOT_MATCH;
			}
			String sign = tokenSplits[2];
			Long endTime = Long.valueOf(descSplits[descSplits.length-1]);
			if (endTime < System.currentTimeMillis()) {
				return TokenResult.EXPIRE;
			}
			boolean vefy = RSAUtil.vefySign(openKey+desc, sign, null);
			if (vefy) {
				updateCache.put(tokenHash, 1);//将更新token标记为已使用
				String common_token = buildToken(openKey, null, TokenType.COMMON_TOKEN);
				String update_token = buildToken(openKey, null, TokenType.REFRESH_TOKEN);
				Map<String,String> tokenMap=new HashMap<>(2);
				tokenMap.put(COMMON_TOKEN, common_token);
				tokenMap.put(REFRESH_TOKEN, update_token);
				return tokenMap;
			} else
				return TokenResult.VAFY_SIGN_ERR;
		} catch (Exception e) {
			log.error("验证token异常{}", e);
			return TokenResult.TOKEN_FORMAT_ERR;
		}
	}
	@Override
	public Map<keyWordDesc, Object> getKeyWordDesc(Object keyWordDesc) {
		if(null==keyWordDesc||keyWordDesc instanceof TokenResult)return null;
		String[] descArr = keyWordDesc.toString().split(TOKEN_DESC_SPLIT);
		 Map<keyWordDesc, Object> res=new HashMap<>(descArr.length);
		 res.put(TokenBusiness.keyWordDesc.OPENKEY, descArr[0]);
		 res.put(TokenBusiness.keyWordDesc.TYPE, descArr[1]);
		 res.put(TokenBusiness.keyWordDesc.ENDTIME, Long.parseLong(descArr[2]));
		 if(TokenType.COMMON_TOKEN.type.equals(descArr[1])){
			 res.put(TokenBusiness.keyWordDesc.LIMIT,TokenType.COMMON_TOKEN.limit);
		 }else if(TokenType.REFRESH_TOKEN.type.equals(descArr[1])){
			 res.put(TokenBusiness.keyWordDesc.LIMIT,TokenType.REFRESH_TOKEN.limit); 
		 }
		return res;
	}
	public static void main(String[] args) {
		TokenBusinessImpl impl=new TokenBusinessImpl();
		String buildToken = impl.buildToken("1", null, TokenType.COMMON_TOKEN);
		Object vafyToken = impl.vafyToken(buildToken);
		Map<keyWordDesc, Object> keyWordDesc = impl.getKeyWordDesc(vafyToken);
		System.out.println(keyWordDesc);
		
	}

	

}
